home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / disk-man / mtools-3.000 / mtools-3 / mtools-3.0 / fat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-08  |  8.6 KB  |  379 lines

  1. #include "sysincludes.h"
  2. #include "msdos.h"
  3. #include "stream.h"
  4. #include "mtools.h"
  5. #include "fsP.h"
  6.  
  7. extern Stream_t *default_drive;
  8.  
  9. /*
  10.  * Fat 12 encoding:
  11.  *    |    byte n     |   byte n+1    |   byte n+2    |
  12.  *    |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
  13.  *    | | | | | | | | | | | | | | | | | | | | | | | | |
  14.  *    | n+0.0 | n+0.5 | n+1.0 | n+1.5 | n+2.0 | n+2.5 |
  15.  *        \_____  \____   \______/________/_____   /
  16.  *          ____\______\________/   _____/  ____\_/
  17.  *         /     \      \          /       /     \
  18.  *    | n+1.5 | n+0.0 | n+0.5 | n+2.0 | n+2.5 | n+1.0 |
  19.  *    |      FAT entry k      |    FAT entry k+1      |
  20.  */
  21.  
  22.  /*
  23.  * Get and decode a FAT (file allocation table) entry.  Returns the cluster
  24.  * number on success or 1 on failure.
  25.  */
  26.  
  27. static unsigned int fat12_decode(Fs_t *Stream, unsigned int num)
  28. {
  29.     DeclareThis(Fs_t);
  30.     unsigned int start = num * 3 / 2;
  31.     unsigned char *address = This->fat_buf + start;
  32.  
  33.     if (num < 2 || start + 1 > (This->fat_len * This->sector_size))
  34.         return 1;
  35.     
  36.     if (num & 1)
  37.         return ((address[1] & 0xff) << 4) | ((address[0] & 0xf0 ) >> 4);
  38.     else
  39.         return ((address[1] & 0xf) << 8) | (address[0] & 0xff );
  40. }
  41.  
  42.  
  43.  
  44.  
  45. /*
  46.  * Puts a code into the FAT table.  Is the opposite of fat_decode().  No
  47.  * sanity checking is done on the code.  Returns a 1 on error.
  48.  */
  49. static int fat12_encode(Fs_t *Stream, unsigned int num, unsigned int code)
  50. {
  51.     DeclareThis(Fs_t);
  52.  
  53.     int start = num * 3 / 2;
  54.     unsigned char *address=This->fat_buf + start;
  55.  
  56.     if (num < 2 || start + 1 > (This->fat_len * This->sector_size))
  57.         return(1);
  58.  
  59.     This->fat_dirty = 1;
  60.     if (num & 1) {
  61.         /* (odd) not on byte boundary */
  62.         address[0] = (address[0] & 0x0f) | ((code << 4) & 0xf0);
  63.         address[1] = (code >> 4) & 0xff;
  64.     } else {
  65.         /* (even) on byte boundary */
  66.         address[0] = code & 0xff;
  67.         address[1] = (address[1] & 0xf0) | ((code >> 8) & 0x0f);
  68.     }
  69.     return 0;
  70. }
  71.  
  72.  
  73. /*
  74.  * Fat 16 encoding:
  75.  *    |    byte n     |   byte n+1    |
  76.  *    |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
  77.  *    | | | | | | | | | | | | | | | | |
  78.  *    |         FAT entry k           |
  79.  */
  80.  
  81. static unsigned int fat16_decode(Fs_t *Stream, unsigned int num)
  82. {
  83.     DeclareThis(Fs_t);
  84.  
  85.     unsigned int start = num * 2;
  86.     unsigned char *address = This->fat_buf + start;
  87.  
  88.     if (num < 2 || start + 1 > (This->fat_len * This->sector_size))
  89.         return(1);
  90.     return address[0] + (address[1] << 8 );
  91. }
  92.  
  93. static int fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code)
  94. {       
  95.     DeclareThis(Fs_t);
  96.  
  97.     int start = num * 2;
  98.     unsigned char *address = This->fat_buf + start;
  99.  
  100.     if (num < 2 || start + 1 > (This->fat_len * This->sector_size))
  101.         return(1);
  102.     This->fat_dirty = 1;
  103.     address[0] =  code & 0xff;
  104.     address[1] =  code >> 8;
  105.     return(0);
  106. }
  107.  
  108. /*
  109.  * Write the FAT table to the disk.  Up to now the FAT manipulation has
  110.  * been done in memory.  All errors are fatal.  (Might not be too smart
  111.  * to wait till the end of the program to write the table.  Oh well...)
  112.  */
  113.  
  114. void fat_write(Fs_t *This)
  115. {
  116.     int i, dups, ret;
  117.  
  118.     if (!This->fat_dirty)
  119.         return;
  120.  
  121.     dups = This->num_fat;
  122.     if (This->fat_error)
  123.         dups = 1;
  124.     
  125.     for(i=0; i<dups; i++){
  126.         ret = force_write(This->Next,
  127.                   (char *) This->fat_buf,
  128.                   (This->fat_start + i*This->fat_len) * 
  129.                   This->sector_size,
  130.                   This->fat_len * This->sector_size);
  131.         if (ret < This->fat_len * This->sector_size){
  132.             if (ret < 0 ){
  133.                 perror("read error in fat_write");
  134.                 cleanup_and_exit(1);
  135.             } else {
  136.                 fprintf(stderr,"end of file in fat_write\n");
  137.                 cleanup_and_exit(1);
  138.             }
  139.         }     
  140.     }
  141.     This->fat_dirty = 0;
  142. }
  143.  
  144.  
  145. static inline int try_fat12(Fs_t *This)
  146. {
  147.     if (This->num_clus >= FAT12)
  148.         /* too many clusters */
  149.         return -2;
  150.  
  151.     This->end_fat = 0xfff;
  152.     This->last_fat = 0xff6;
  153.     This->fat_decode = fat12_decode;
  154.     This->fat_encode = fat12_encode;
  155.     return 0;
  156. }
  157.  
  158. static inline int try_fat16(Fs_t *This)
  159. {
  160.     if(This->fat_len < NEEDED_FAT_SIZE(This))
  161.         return -2;
  162.     if(This->fat_buf[3] != 0xff)
  163.         return -1;
  164.  
  165.     This->end_fat = 0xffff;
  166.     This->last_fat = 0xfff6;
  167.     This->fat_decode = fat16_decode;
  168.     This->fat_encode = fat16_encode;
  169.     return 0;
  170. }
  171.  
  172. static inline int check_fat(Fs_t *This, int verbose)
  173. {
  174.     int i, f;
  175.     if(mtools_skip_check)
  176.         return 0;
  177.     
  178.     for ( i= 3 ; i <This->num_clus; i++){
  179.         f = This->fat_decode(This,i);
  180.         if (f < This->last_fat && f > This->num_clus){
  181.             if(verbose){
  182.                 fprintf(stderr,
  183.                     "Cluster # at %d too big(%#x)\n", i,f);
  184.                 fprintf(stderr,"Probably non MS-DOS disk\n");
  185.             }
  186.             return -1;
  187.         }
  188.     }
  189.     return 0;
  190. }
  191.  
  192. static inline int try_fat(Fs_t *This, int bits, int verbose)
  193. {
  194.     int ret;
  195.  
  196.     This->fat_bits = bits;
  197.     if (bits == 12)
  198.         ret = try_fat12(This);
  199.     else
  200.         ret = try_fat16(This);
  201.     if(ret)
  202.         return ret;
  203.     else
  204.         return check_fat(This, verbose);
  205. }
  206.  
  207.  
  208. /*
  209.  * Read the entire FAT table into memory.  Crude error detection on wrong
  210.  * FAT encoding scheme.
  211.  */
  212. static int _fat_read(Fs_t *This, struct bootsector *boot, 
  213.              int fat_bits, int nfat)
  214. {
  215.     int ret, ret2;
  216.  
  217.     /* read the FAT sectors */
  218.     ret = force_read(This->Next,
  219.              (char *) This->fat_buf,
  220.              (This->fat_start + nfat * This->fat_len) *
  221.              This->sector_size,
  222.              This->fat_len * This->sector_size);
  223.     if (ret < This->fat_len * This->sector_size){
  224.         if (ret < 0 ){
  225.             perror("read error in fat_read");
  226.             return -1;
  227.         } else {
  228.             fprintf(stderr,"end of file in fat_read\n");
  229.             return -1;
  230.         }
  231.     }
  232.  
  233.     if (!mtools_skip_check &&
  234.         (This->fat_buf[0] || This->fat_buf[1] || This->fat_buf[2])) {
  235.         if((This->fat_buf[0] != boot->descr && boot->descr >= 0xf0 &&
  236.             (This->fat_buf[0] != 0xf9 || boot->descr != 0xf0)) ||
  237.            This->fat_buf[0] < 0xf0){
  238.             fprintf(stderr,
  239.                 "Bad media type, probably non-MSDOS disk\n");
  240.             return -1;
  241.         }
  242.         if(This->fat_buf[1] != 0xff || This->fat_buf[2] != 0xff){
  243.             fprintf(stderr,"Initial byte of fat is not 0xff\n");
  244.             return -1;
  245.         }
  246.     }
  247.  
  248.     switch(fat_bits){
  249.     case 12:
  250.     case 16:
  251.         return try_fat(This, fat_bits, 1);
  252.     case -12:
  253.     case -16:
  254.         return try_fat(This, -fat_bits, 1);
  255.     case 0:
  256.         /* no size given in the configuration file.
  257.          * Figure out a first guess */
  258.  
  259.         if (boot->descr < 0xf0 || boot->dos4 !=0x29)
  260.             fat_bits = 12; /* old DOS */
  261.         else if (!strncmp(boot->fat_type, "FAT12   ", 8))
  262.             fat_bits = 12;
  263.         else if (!strncmp (boot->fat_type, "FAT16   ", 8))
  264.             fat_bits = 16;
  265.         else
  266.             fat_bits = 12;
  267.  
  268.         ret = try_fat(This, fat_bits, nfat);
  269.         if(!ret)
  270.             return 0; /* first try succeeded */
  271.         fat_bits = 16 - fat_bits;
  272.         ret2 = try_fat(This, fat_bits, 1);
  273.         if(ret2 >= ret) /* second try didn't fail as badly as first */
  274.             return ret2;
  275.  
  276.         /* revert to first try because that one failed less badly */
  277.         fat_bits = 16 - fat_bits;
  278.         return try_fat(This, fat_bits, 1);
  279.     default:
  280.         fprintf(stderr,"%d fat bits not supported\n", fat_bits);
  281.         return -3;
  282.     }
  283. }
  284.  
  285.  
  286. /*
  287.  * Read the entire FAT table into memory.  Crude error detection on wrong
  288.  * FAT encoding scheme.
  289.  */
  290. int fat_read(Fs_t *This, struct bootsector *boot, int fat_bits)
  291. {
  292.     int i;
  293.     unsigned int buflen;
  294.     int ret;
  295.  
  296.     /* only the first copy of the FAT */
  297.     buflen = This->fat_len * This->sector_size;
  298.     This->fat_buf = (unsigned char *) malloc(buflen);
  299.     if (This->fat_buf == NULL) {
  300.         perror("fat_read: malloc");
  301.         return -1;
  302.     }
  303.  
  304.     This->fat_error = 0;
  305.     This->fat_dirty = 0;
  306.  
  307.     for (i=0; i< This->num_fat; i++){
  308.         if(i)
  309.             fprintf(stderr,
  310.                 "Bad FAT for drive %c, trying secondary copy\n",
  311.                 This->drive);
  312.         ret =  _fat_read(This, boot, fat_bits,i);
  313.         switch(ret){
  314.         case 0:
  315.             goto break_2;
  316.         case -1:
  317.             continue;
  318.         case -2:
  319.             /* the return value suggests a different fat,
  320.              * independently of the read data */
  321.             if(fat_bits > 0 ){                
  322.                 fprintf(stderr,
  323.                     "%c: %d bit FAT. sure ? (Use -%d in the device configuration file to bypass.)\n",
  324.                     This->drive, fat_bits, fat_bits);
  325.                 return -2;
  326.             } else if(fat_bits < 0)
  327.                 /* the user insisted. Let it pass */
  328.                 goto break_2;
  329.             /* FALLTHROUGH */
  330.         case -3:
  331.             return -1;
  332.         }
  333.     }
  334.  
  335.  break_2:
  336.     if(i == This->num_fat){
  337.         fprintf(stderr, "Could not read FAT for %c\n", This->drive);
  338.         return -1;
  339.     }
  340.  
  341.     /*
  342.      * Let's see if the length of the FAT table is appropriate for
  343.      * the number of clusters and the encoding scheme.
  344.      * Older versions of mtools goofed this up. If the env var
  345.      * MTOOLS_FAT_COMPATIBILITY is defined, skip this check in order to read
  346.      * disks formatted by an old version.
  347.      */
  348.     if(!mtools_fat_compatibility &&
  349.        This->fat_len > NEEDED_FAT_SIZE(This) + 1){
  350.         fprintf(stderr,
  351.             "fat_read: Wrong FAT encoding for drive %c."
  352.             "(len=%d instead of %d?)\n",
  353.             This->drive, This->fat_len, NEEDED_FAT_SIZE(This));
  354.         fprintf(stderr,
  355.             "Set MTOOLS_FAT_COMPATIBILITY to suppress"
  356.             " this message\n");
  357.         return -1;
  358.     }
  359.     return 0;
  360. }
  361.  
  362.  
  363. unsigned int get_next_free_cluster(Fs_t *This, unsigned int last)
  364. {
  365.     int i;
  366.  
  367.     if ( last < 2)
  368.         last = 1;
  369.     for (i=last+1; i< This->num_clus+2; i++){
  370.         if (!This->fat_decode(This, i))
  371.             return i;
  372.     }
  373.     for(i=2; i < last+1; i++){
  374.         if (!This->fat_decode(This, i))
  375.             return i;
  376.     }
  377.     return 1;
  378. }
  379.